﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Geotools.Geometries;
using AzukiMap.MapSource;
using AzukiMap.Map;
using System.Collections.Generic;

namespace AzukiMap.Layer
{
    public abstract class MercatorQuadLayer : TiledLayer
    {
        MercatorQuadTileSource _mercatorQuadSource;

        public MercatorQuadLayer(MercatorQuadTileSource mapSource, MapCanvas mapCanvas, string name)
            : base(mapSource, mapCanvas, name, mapSource.MaxExtent)
        {
            _mercatorQuadSource = mapSource;
        }

        protected override string CreateTileReqString(double tileScale, int tileLeft, int tileTop)
        {
            throw new NotImplementedException();
        }

        protected override GTCoordinate GetTileOrigin(double lon, double lat, double tileScale)
        {
            int zoomLevel = GetScaleLevel(tileScale); 
            GTCoordinate pixPoint = GeoToPixel(lon, lat, zoomLevel);
            GTCoordinate origin = GetTileOriginNum((int)pixPoint.X, (int)pixPoint.Y);

            return new GTCoordinate(origin.X * _mercatorQuadSource.TileWidth, origin.Y * _mercatorQuadSource.TileHeight);
        }

        protected override GTCoordinate GetGeoPointFromTileCoord(int pixelX, int pixelY, double tileScale)
        {
            int zoomLevel = GetScaleLevel(tileScale);
            int mapSize = GetMapSize(zoomLevel);

            double lon = (double)pixelX / mapSize * 360 - 180;
            double radY = ((double)pixelY / mapSize - 0.5) / -1 * (2 * Math.PI);
            double lat = Math.Atan(Math.Sinh(radY)) * (180 / Math.PI);

            return new GTCoordinate(lon, lat);
        }

        protected int GetScaleLevel(double tileScale)
        {
            return _mercatorQuadSource.ScaleLevels[tileScale];
        }

        protected int GetMapSize(int zoomLevel)
        {
            int size = (int)(_mercatorQuadSource.TileWidth * 2 * Math.Pow(2.0, (double)(zoomLevel - 1)));
            return size;
        }

        protected GTCoordinate GeoToPixel(double lon, double lat, int zoomLevel)
        {   
            double x = (lon + 180) / 360; 
            double sinLat = Math.Sin(lat * Math.PI / 180);
            double radY = 0.5 * Math.Log((1 + sinLat) / (1 - sinLat));
            double y = radY / (2 * Math.PI) * -1 + 0.5;

            int mapSize = GetMapSize(zoomLevel);
            int pixelX = (int)(x * mapSize + 0.5);
            int pixelY = (int)(y * mapSize + 0.5);

            return new GTCoordinate(pixelX, pixelY);
        }

        protected GTCoordinate GetTileOriginNum(int pixX, int pixY)
        {
            int orgX = pixX / _mercatorQuadSource.TileWidth;
            int orgY = pixY / _mercatorQuadSource.TileHeight;

            return new GTCoordinate(orgX, orgY);
        }

        protected override double GetTileScale(double scale)
        {
            double nearestScale = 0;
            foreach (double tileScale in _mercatorQuadSource.Scales)
            {
                if (tileScale > scale)
                {
                    nearestScale = tileScale;
                    break;
                }
            }

            if (nearestScale == 0)
            {
                nearestScale = _mercatorQuadSource.Scales[0];
            }
            return nearestScale;
        }
    }
}
